﻿using Basic.FormCollect;
using Basic.FormCollect.Model;
using Basic.FormModel.DB;
using Basic.FormModel.FormViewCol;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.FormView.Model;
using Basic.FormRemoteModel.PageLayout.Model;
using Basic.UserFormService.Interface;
using SqlSugar;
using WeDonekRpc.Helper;
using WeDonekRpc.SqlSugar;
using WeDonekRpc.SqlSugar.VirtualQuery;

namespace Basic.UserFormService.Extend
{
    internal class FormViewGenerateService : IFormViewGenerateService
    {
        private readonly IQueryTableCollect _Table;
        private readonly IQueryColumnCollect _Column;
        private readonly ICustomFormCollect _Form;
        private readonly IFormViewCollect _FormView;
        private readonly IFormViewColCollect _ViewCol;
        public FormViewGenerateService ( IQueryTableCollect table,
            IQueryColumnCollect column,
            ICustomFormCollect form,
            IFormViewColCollect viewCol,
            IFormViewCollect formView )
        {
            this._Column = column;
            this._ViewCol = viewCol;
            this._Form = form;
            this._Table = table;
            this._FormView = formView;
        }
        private Dictionary<long, string> _TableName;
        private Dictionary<long, FormViewColBase> _Cols;
        private Dictionary<long, PhyTableCol> _SourceCol;
        public void GenerateView ( long formId )
        {
            DBFormView sour = this._FormView.Find(formId);
            if ( sour == null )
            {
                throw new ErrorException("form.view.no.config");
            }
            this._Cols = this._ViewCol.GetsByFormId<FormViewColBase>(sour.FormId).ToDictionary(a => a.Id, a => a);
            this._Check(sour);
            string name = this._Form.Get(sour.FormId, a => a.TableName);
            QueryStruct body = this._GetStruct(sour);
            this._FormView.GenerateView(sour, name, body);
        }
        private void _Check ( DBFormView sour )
        {
            if ( this._Cols.Count == 0 )
            {
                throw new ErrorException("form.view.col.null");
            }
        }
        private QueryStruct _GetStruct ( DBFormView sour )
        {
            long[] tableId = sour.ViewTable.Join.ConvertAll(a => a.TableId).Add(sour.ViewTable.TableId);
            this._SourceCol = this._Column.GetCols(tableId);
            this._TableName = this._Table.GetTableName(tableId);
            TableStruct table = this._GetTable(sour);
            return new QueryStruct
            {
                Table = table,
                Where = this._GetWhere(sour.WhereList),
                Having = this._GetHaving(sour.HavingSet),
                GroupBy = this._GetGroupBy(sour.GroupBy),
                Select = this._Cols.ConvertAll(i =>
                {
                    FormViewColBase c = i.Value;
                    return new SelectStruct
                    {
                        Name = c.Name,
                        Func = c.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                        DateType = dateType,
                        Format = format,
                        Table = this._TableName[c.TableId],
                        Alias = c.Alias
                    };
                })
            };
        }

        private GroupByStruct[] _GetGroupBy ( long[] colId )
        {
            return colId.IsNull() ? null : colId.ConvertAll(c =>
            {
                FormViewColBase col = this._Cols[c];
                return new GroupByStruct
                {
                    Name = col.Name,
                    Table = this._TableName[col.TableId],
                    Func = col.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                    DateType = dateType,
                    Format = format,
                };
            });
        }
        private HavingCol? _GetHaving ( ViewHaving having )
        {
            if ( having == null || having.ColId.HasValue == false )
            {
                return null;
            }
            FormViewColBase col = this._Cols[having.ColId.Value];
            return new HavingCol
            {
                DbType = col.DataType.GetDbType(),
                ConditionalType = having.Mode.GetConditionalType(),
                Name = col.Name,
                Table = this._TableName[col.TableId],
                Value = having.Value.GetFilterValue(),
                Func = col.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                DateType = dateType,
                Format = format
            };
        }


        private IWhereCol[] _GetWhere ( PageFilterParam[] where )
        {
            if ( where.IsNull() )
            {
                return null;
            }
            return where.ConvertAll<PageFilterParam, IWhereCol>(c =>
            {
                PhyTableCol col = this._SourceCol[c.ColId.Value];
                if ( c.Children.IsNull() )
                {
                    return new WhereCol
                    {
                        ConditionalType = c.Mode.Value.GetConditionalType(),
                        DbType = col.DataType.GetDbType(),
                        Func = c.Mode.Value == PageFilterMode.Between ? FuncType.Between : FuncType.None,
                        IsAnd = c.IsAnd,
                        Table = new WhereTable
                        {
                            Table = this._TableName[col.TableId]
                        },
                        Name = col.Name,
                        Value = c.Value.GetFilterValue()
                    };
                }
                WhereCollect collect = new WhereCollect
                {
                    Collect = c.Children.ConvertAll(a =>
                    {
                        PhyTableCol col = this._SourceCol[a.ColId.Value];
                        return new WhereCol
                        {
                            ConditionalType = a.Mode.Value.GetConditionalType(),
                            DbType = col.DataType.GetDbType(),
                            Func = a.Mode.Value == PageFilterMode.Between ? FuncType.Between : FuncType.None,
                            IsAnd = a.IsAnd,
                            Table = new WhereTable
                            {
                                Table = this._TableName[col.TableId]
                            },
                            Name = col.Name,
                            Value = a.Value.GetFilterValue()
                        };
                    })
                };
                collect.Collect[0].IsAnd = c.IsAnd;
                return collect;
            });
        }
        private TableStruct _GetTable ( DBFormView sour )
        {
            FormViewTable table = sour.ViewTable;
            return new TableStruct
            {
                Name = this._TableName[table.TableId],
                JoinType = SqlSugar.JoinType.Inner,
                Foreign = table.Join.ConvertAll(c =>
                {
                    return new TableStruct
                    {
                        Name = this._TableName[c.TableId],
                        JoinType = (SqlSugar.JoinType)(int)c.JoinType,
                        Filter = c.JoinOn.ToDictionary(a => this._SourceCol[a.Key].Name, a => this._SourceCol[a.Value].Name)
                    };
                })
            };
        }
    }
}
